home *** CD-ROM | disk | FTP | other *** search
- /*
- * main_beos.cpp - Startup code for BeOS
- *
- * Basilisk II (C) 1997-2001 Christian Bauer
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- #include <AppKit.h>
- #include <InterfaceKit.h>
- #include <KernelKit.h>
- #include <StorageKit.h>
-
- #include <unistd.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
-
- #include "sysdeps.h"
- #include "cpu_emulation.h"
- #include "xpram.h"
- #include "timer.h"
- #include "video.h"
- #include "rom_patches.h"
- #include "prefs.h"
- #include "prefs_editor.h"
- #include "sys.h"
- #include "user_strings.h"
- #include "version.h"
- #include "main.h"
-
- #include "sheep_driver.h"
-
- #define DEBUG 0
- #include "debug.h"
-
-
- // Constants
- const char APP_SIGNATURE[] = "application/x-vnd.cebix-BasiliskII";
- const char ROM_FILE_NAME[] = "ROM";
- const char RAM_AREA_NAME[] = "Macintosh RAM";
- const char ROM_AREA_NAME[] = "Macintosh ROM";
- const uint32 MSG_START = 'strt'; // Emulator start message
- const uint32 ROM_AREA_SIZE = 0x500000; // Enough to hold PowerMac ROM (for powerrom_cpu)
-
- // Prototypes
- #if __POWERPC__
- static void sigsegv_handler(vregs *r);
- #endif
-
-
- // Application object
- class BasiliskII : public BApplication {
- public:
- BasiliskII() : BApplication(APP_SIGNATURE)
- {
- // Find application directory and cwd to it
- app_info the_info;
- GetAppInfo(&the_info);
- BEntry the_file(&the_info.ref);
- BEntry the_dir;
- the_file.GetParent(&the_dir);
- BPath the_path;
- the_dir.GetPath(&the_path);
- chdir(the_path.Path());
-
- // Initialize other variables
- rom_area = ram_area = -1;
- xpram_thread = tick_thread = -1;
- xpram_thread_active = true;
- tick_thread_active = true;
- AllowQuitting = true;
- }
- virtual void ReadyToRun(void);
- virtual void MessageReceived(BMessage *msg);
- void StartEmulator(void);
- virtual bool QuitRequested(void);
- virtual void Quit(void);
-
- thread_id xpram_thread; // XPRAM watchdog
- thread_id tick_thread; // 60Hz thread
-
- volatile bool xpram_thread_active; // Flag for quitting the XPRAM thread
- volatile bool tick_thread_active; // Flag for quitting the 60Hz thread
-
- bool AllowQuitting; // Flag: Alt-Q quitting allowed
-
- private:
- static status_t emul_func(void *arg);
- static status_t tick_func(void *arg);
- static status_t xpram_func(void *arg);
- static void sigsegv_invoc(int sig, void *arg, vregs *r);
-
- void init_rom(void);
- void load_rom(void);
-
- area_id rom_area; // ROM area ID
- area_id ram_area; // RAM area ID
-
- struct sigaction sigsegv_action; // Data access exception signal (of emulator thread)
-
- // Exceptions
- class area_error {};
- class file_open_error {};
- class file_read_error {};
- class rom_size_error {};
- };
-
- static BasiliskII *the_app;
-
-
- // CPU and FPU type, addressing mode
- int CPUType;
- bool CPUIs68060;
- int FPUType;
- bool TwentyFourBitAddressing;
-
-
- // Global variables for PowerROM CPU
- thread_id emul_thread = -1; // Emulator thread
-
- #if __POWERPC__
- int sheep_fd = -1; // fd of sheep driver
- #endif
-
-
- /*
- * Create application object and start it
- */
-
- int main(int argc, char **argv)
- {
- the_app = new BasiliskII();
- the_app->Run();
- delete the_app;
- return 0;
- }
-
-
- /*
- * Run application
- */
-
- void BasiliskII::ReadyToRun(void)
- {
- // Initialize variables
- RAMBaseHost = NULL;
- ROMBaseHost = NULL;
- srand(real_time_clock());
- tzset();
-
- // Print some info
- printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
- printf(" %s\n", GetString(STR_ABOUT_TEXT2));
-
- // Delete old areas
- area_id old_ram_area = find_area(RAM_AREA_NAME);
- if (old_ram_area > 0)
- delete_area(old_ram_area);
- area_id old_rom_area = find_area(ROM_AREA_NAME);
- if (old_rom_area > 0)
- delete_area(old_rom_area);
-
- // Read preferences
- int argc = 0;
- char **argv = NULL;
- PrefsInit(argc, argv);
-
- // Init system routines
- SysInit();
-
- // Show preferences editor (or start emulator directly)
- if (!PrefsFindBool("nogui"))
- PrefsEditor();
- else
- PostMessage(MSG_START);
- }
-
-
- /*
- * Message received
- */
-
- void BasiliskII::MessageReceived(BMessage *msg)
- {
- switch (msg->what) {
- case MSG_START:
- StartEmulator();
- break;
- default:
- BApplication::MessageReceived(msg);
- }
- }
-
-
- /*
- * Start emulator
- */
-
- void BasiliskII::StartEmulator(void)
- {
- char str[256];
-
- #if REAL_ADDRESSING
- // Open sheep driver and remap low memory
- sheep_fd = open("/dev/sheep", 0);
- if (sheep_fd < 0) {
- sprintf(str, GetString(STR_NO_SHEEP_DRIVER_ERR), strerror(sheep_fd), sheep_fd);
- ErrorAlert(str);
- PostMessage(B_QUIT_REQUESTED);
- return;
- }
- status_t res = ioctl(sheep_fd, SHEEP_UP);
- if (res < 0) {
- sprintf(str, GetString(STR_SHEEP_UP_ERR), strerror(res), res);
- ErrorAlert(str);
- PostMessage(B_QUIT_REQUESTED);
- return;
- }
- #endif
-
- // Create area for Mac RAM
- RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
- if (RAMSize < 1024*1024) {
- WarningAlert(GetString(STR_SMALL_RAM_WARN));
- RAMSize = 1024*1024;
- }
-
- RAMBaseHost = (uint8 *)0x10000000;
- ram_area = create_area(RAM_AREA_NAME, (void **)&RAMBaseHost, B_BASE_ADDRESS, RAMSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
- if (ram_area < 0) {
- ErrorAlert(GetString(STR_NO_RAM_AREA_ERR));
- PostMessage(B_QUIT_REQUESTED);
- return;
- }
- D(bug("RAM area %ld at %p\n", ram_area, RAMBaseHost));
-
- // Create area and load Mac ROM
- try {
- init_rom();
- } catch (area_error) {
- ErrorAlert(GetString(STR_NO_ROM_AREA_ERR));
- PostMessage(B_QUIT_REQUESTED);
- return;
- } catch (file_open_error) {
- ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
- PostMessage(B_QUIT_REQUESTED);
- return;
- } catch (file_read_error) {
- ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
- PostMessage(B_QUIT_REQUESTED);
- return;
- } catch (rom_size_error) {
- ErrorAlert(GetString(STR_ROM_SIZE_ERR));
- PostMessage(B_QUIT_REQUESTED);
- return;
- }
-
- // Initialize everything
- if (!InitAll()) {
- PostMessage(B_QUIT_REQUESTED);
- return;
- }
-
- // Write protect ROM
- set_area_protection(rom_area, B_READ_AREA);
-
- // Disallow quitting with Alt-Q from now on
- AllowQuitting = false;
-
- // Start XPRAM watchdog thread
- xpram_thread = spawn_thread(xpram_func, "XPRAM Watchdog", B_LOW_PRIORITY, this);
- resume_thread(xpram_thread);
-
- // Start 60Hz interrupt
- tick_thread = spawn_thread(tick_func, "60Hz", B_REAL_TIME_PRIORITY, this);
- resume_thread(tick_thread);
-
- // Start emulator thread
- emul_thread = spawn_thread(emul_func, "MacOS", B_NORMAL_PRIORITY, this);
- resume_thread(emul_thread);
- }
-
-
- /*
- * Quit emulator
- */
-
- void QuitEmulator(void)
- {
- the_app->AllowQuitting = true;
- be_app->PostMessage(B_QUIT_REQUESTED);
- exit_thread(0);
- }
-
- bool BasiliskII::QuitRequested(void)
- {
- if (AllowQuitting)
- return BApplication::QuitRequested();
- else
- return false;
- }
-
- void BasiliskII::Quit(void)
- {
- status_t l;
-
- // Stop 60Hz interrupt
- if (tick_thread > 0) {
- tick_thread_active = false;
- wait_for_thread(tick_thread, &l);
- }
-
- // Wait for emulator thread to finish
- if (emul_thread > 0)
- wait_for_thread(emul_thread, &l);
-
- // Exit 680x0 emulation
- Exit680x0();
-
- // Stop XPRAM watchdog thread
- if (xpram_thread > 0) {
- xpram_thread_active = false;
- suspend_thread(xpram_thread); // Wake thread up from snooze()
- snooze(1000);
- resume_thread(xpram_thread);
- wait_for_thread(xpram_thread, &l);
- }
-
- // Deinitialize everything
- ExitAll();
-
- // Delete ROM area
- if (rom_area >= 0)
- delete_area(rom_area);
-
- // Delete RAM area
- if (ram_area >= 0)
- delete_area(ram_area);
-
- #if REAL_ADDRESSING
- // Unmap low memory and close memory mess driver
- if (sheep_fd >= 0) {
- ioctl(sheep_fd, SHEEP_DOWN);
- close(sheep_fd);
- }
- #endif
-
- // Exit system routines
- SysExit();
-
- // Exit preferences
- PrefsExit();
-
- BApplication::Quit();
- }
-
-
- /*
- * Create area for ROM (sets rom_area) and load ROM file
- *
- * area_error : Cannot create area
- * file_open_error: Cannot open ROM file
- * file_read_error: Cannot read ROM file
- */
-
- void BasiliskII::init_rom(void)
- {
- // Create area for ROM
- ROMBaseHost = (uint8 *)0x40800000;
- rom_area = create_area(ROM_AREA_NAME, (void **)&ROMBaseHost, B_BASE_ADDRESS, ROM_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
- if (rom_area < 0)
- throw area_error();
- D(bug("ROM area %ld at %p\n", rom_area, ROMBaseHost));
-
- // Load ROM
- load_rom();
- }
-
-
- /*
- * Load ROM file
- *
- * file_open_error: Cannot open ROM file
- * file_read_error: Cannot read ROM file
- */
-
- void BasiliskII::load_rom(void)
- {
- // Get rom file path from preferences
- const char *rom_path = PrefsFindString("rom");
-
- // Try to open ROM file
- BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY);
- if (file.InitCheck() != B_NO_ERROR)
- throw file_open_error();
-
- printf(GetString(STR_READING_ROM_FILE));
-
- // Is the ROM size correct?
- off_t rom_size = 0;
- file.GetSize(&rom_size);
- if (rom_size != 64*1024 && rom_size != 128*1024 && rom_size != 256*1024 && rom_size != 512*1024 && rom_size != 1024*1024)
- throw rom_size_error();
-
- uint8 *rom = new uint8[rom_size]; // Reading directly into the area doesn't work
- ssize_t actual = file.Read((void *)rom, rom_size);
- if (actual == rom_size)
- memcpy(ROMBaseHost, rom, rom_size);
- delete[] rom;
- if (actual != rom_size)
- throw file_read_error();
- ROMSize = rom_size;
- }
-
-
- /*
- * Emulator thread function
- */
-
- status_t BasiliskII::emul_func(void *arg)
- {
- BasiliskII *obj = (BasiliskII *)arg;
-
- #if __POWERPC__
- // Install data access signal handler
- sigemptyset(&obj->sigsegv_action.sa_mask);
- obj->sigsegv_action.sa_handler = (__signal_func_ptr)(obj->sigsegv_invoc);
- obj->sigsegv_action.sa_flags = 0;
- obj->sigsegv_action.sa_userdata = arg;
- sigaction(SIGSEGV, &obj->sigsegv_action, NULL);
- #endif
-
- // Exceptions will send signals
- disable_debugger(true);
-
- // Start 68k and jump to ROM boot routine
- Start680x0();
-
- // Quit program
- obj->AllowQuitting = true;
- be_app->PostMessage(B_QUIT_REQUESTED);
- return 0;
- }
-
-
- /*
- * Code was patched, flush caches if neccessary (i.e. when using a real 680x0
- * or a dynamically recompiling emulator)
- */
-
- void FlushCodeCache(void *start, uint32 size)
- {
- }
-
-
- /*
- * Interrupt flags (must be handled atomically!)
- */
-
- uint32 InterruptFlags = 0;
-
- void SetInterruptFlag(uint32 flag)
- {
- atomic_or((int32 *)&InterruptFlags, flag);
- }
-
- void ClearInterruptFlag(uint32 flag)
- {
- atomic_and((int32 *)&InterruptFlags, ~flag);
- }
-
-
- /*
- * 60Hz thread (really 60.15Hz)
- */
-
- status_t BasiliskII::tick_func(void *arg)
- {
- BasiliskII *obj = (BasiliskII *)arg;
- int tick_counter = 0;
- bigtime_t current = system_time();
-
- while (obj->tick_thread_active) {
-
- // Wait
- current += 16625;
- snooze_until(current, B_SYSTEM_TIMEBASE);
-
- // Pseudo Mac 1Hz interrupt, update local time
- if (++tick_counter > 60) {
- tick_counter = 0;
- WriteMacInt32(0x20c, TimerDateTime());
- SetInterruptFlag(INTFLAG_1HZ);
- TriggerInterrupt();
- }
-
- // Trigger 60Hz interrupt
- SetInterruptFlag(INTFLAG_60HZ);
- TriggerInterrupt();
- }
- return 0;
- }
-
-
- /*
- * XPRAM watchdog thread (saves XPRAM every minute)
- */
-
- status_t BasiliskII::xpram_func(void *arg)
- {
- uint8 last_xpram[256];
- memcpy(last_xpram, XPRAM, 256);
-
- while (((BasiliskII *)arg)->xpram_thread_active) {
- snooze(60*1000000);
- if (memcmp(last_xpram, XPRAM, 256)) {
- memcpy(last_xpram, XPRAM, 256);
- SaveXPRAM();
- }
- }
- return 0;
- }
-
-
- /*
- * Display error alert
- */
-
- void ErrorAlert(const char *text)
- {
- if (PrefsFindBool("nogui")) {
- printf(GetString(STR_SHELL_ERROR_PREFIX), text);
- return;
- }
- VideoQuitFullScreen();
- char str[256];
- sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text);
- BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
- alert->Go();
- }
-
-
- /*
- * Display warning alert
- */
-
- void WarningAlert(const char *text)
- {
- if (PrefsFindBool("nogui")) {
- printf(GetString(STR_SHELL_WARNING_PREFIX), text);
- return;
- }
- char str[256];
- sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
- BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
- alert->Go();
- }
-
-
- /*
- * Display choice alert
- */
-
- bool ChoiceAlert(const char *text, const char *pos, const char *neg)
- {
- char str[256];
- sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text);
- BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT);
- return alert->Go() == 0;
- }
-
-
- /*
- * SEGV handler
- */
-
- #if __POWERPC__
- static uint32 segv_r[32];
-
- asm void BasiliskII::sigsegv_invoc(register int sig, register void *arg, register vregs *r)
- {
- mflr r0
- stw r0,8(r1)
- stwu r1,-56(r1)
-
- lwz r3,segv_r(r2)
- stmw r13,13*4(r3)
-
- mr r3,r5
- bl sigsegv_handler
-
- lwz r3,segv_r(r2)
- lmw r13,13*4(r3)
-
- lwz r0,56+8(r1)
- mtlr r0
- addi r1,r1,56
- blr
- }
-
- static void sigsegv_handler(vregs *r)
- {
- // Fetch volatile registers
- segv_r[0] = r->r0;
- segv_r[1] = r->r1;
- segv_r[2] = r->r2;
- segv_r[3] = r->r3;
- segv_r[4] = r->r4;
- segv_r[5] = r->r5;
- segv_r[6] = r->r6;
- segv_r[7] = r->r7;
- segv_r[8] = r->r8;
- segv_r[9] = r->r9;
- segv_r[10] = r->r10;
- segv_r[11] = r->r11;
- segv_r[12] = r->r12;
-
- // Get opcode and divide into fields
- uint32 opcode = *(uint32 *)r->pc;
- uint32 primop = opcode >> 26;
- uint32 exop = (opcode >> 1) & 0x3ff;
- uint32 ra = (opcode >> 16) & 0x1f;
- uint32 rb = (opcode >> 11) & 0x1f;
- uint32 rd = (opcode >> 21) & 0x1f;
- uint32 imm = opcode & 0xffff;
-
- // Analyze opcode
- enum {
- TYPE_UNKNOWN,
- TYPE_LOAD,
- TYPE_STORE
- } transfer_type = TYPE_UNKNOWN;
- enum {
- SIZE_UNKNOWN,
- SIZE_BYTE,
- SIZE_HALFWORD,
- SIZE_WORD
- } transfer_size = SIZE_UNKNOWN;
- enum {
- MODE_UNKNOWN,
- MODE_NORM,
- MODE_U,
- MODE_X,
- MODE_UX
- } addr_mode = MODE_UNKNOWN;
- switch (primop) {
- case 31:
- switch (exop) {
- case 23: // lwzx
- transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
- case 55: // lwzux
- transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
- case 87: // lbzx
- transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
- case 119: // lbzux
- transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
- case 151: // stwx
- transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
- case 183: // stwux
- transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
- case 215: // stbx
- transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
- case 247: // stbux
- transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
- case 279: // lhzx
- transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
- case 311: // lhzux
- transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
- case 343: // lhax
- transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
- case 375: // lhaux
- transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
- case 407: // sthx
- transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break;
- case 439: // sthux
- transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break;
- }
- break;
-
- case 32: // lwz
- transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
- case 33: // lwzu
- transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
- case 34: // lbz
- transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
- case 35: // lbzu
- transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
- case 36: // stw
- transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
- case 37: // stwu
- transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
- case 38: // stb
- transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
- case 39: // stbu
- transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
- case 40: // lhz
- transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
- case 41: // lhzu
- transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
- case 42: // lha
- transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
- case 43: // lhau
- transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
- case 44: // sth
- transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break;
- case 45: // sthu
- transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break;
- }
-
- // Calculate effective address
- uint32 addr = 0;
- switch (addr_mode) {
- case MODE_X:
- case MODE_UX:
- if (ra == 0)
- addr = segv_r[rb];
- else
- addr = segv_r[ra] + segv_r[rb];
- break;
- case MODE_NORM:
- case MODE_U:
- if (ra == 0)
- addr = (int32)(int16)imm;
- else
- addr = segv_r[ra] + (int32)(int16)imm;
- break;
- }
-
- // Ignore ROM writes
- if (transfer_type == TYPE_STORE && addr >= (uint32)ROMBaseHost && addr < (uint32)ROMBaseHost + ROMSize) {
- // D(bug("WARNING: %s write access to ROM at %p, 68k pc %p\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->pc));
- if (addr_mode == MODE_U || addr_mode == MODE_UX)
- segv_r[ra] = addr;
- r->pc += 4;
- goto rti;
- }
-
- // For all other errors, jump into debugger
- char str[256];
- sprintf(str, "SIGSEGV\n"
- " pc %08lx lr %08lx ctr %08lx msr %08lx\n"
- " xer %08lx cr %08lx fpscr %08lx\n"
- " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n"
- " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n"
- " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n"
- " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n"
- " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n"
- " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n"
- " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n"
- " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n",
- r->pc, r->lr, r->ctr, r->msr,
- r->xer, r->cr, r->fpscr,
- r->r0, r->r1, r->r2, r->r3,
- r->r4, r->r5, r->r6, r->r7,
- r->r8, r->r9, r->r10, r->r11,
- r->r12, segv_r[13], segv_r[14], segv_r[15],
- segv_r[16], segv_r[17], segv_r[18], segv_r[19],
- segv_r[20], segv_r[21], segv_r[22], segv_r[23],
- segv_r[24], segv_r[25], segv_r[26], segv_r[27],
- segv_r[28], segv_r[29], segv_r[30], segv_r[31]);
- disable_debugger(false);
- debugger(str);
- QuitEmulator();
- return;
-
- rti:
- // Restore volatile registers
- r->r0 = segv_r[0];
- r->r1 = segv_r[1];
- r->r2 = segv_r[2];
- r->r3 = segv_r[3];
- r->r4 = segv_r[4];
- r->r5 = segv_r[5];
- r->r6 = segv_r[6];
- r->r7 = segv_r[7];
- r->r8 = segv_r[8];
- r->r9 = segv_r[9];
- r->r10 = segv_r[10];
- r->r11 = segv_r[11];
- r->r12 = segv_r[12];
- }
- #endif
-